package com.llap.exp190929.service;

import com.llap.exp190929.entity.Book;
import com.llap.exp190929.entity.BookType;
import com.llap.exp190929.repository.BookRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;

@Service
@AllArgsConstructor
@Slf4j
public class BookService {
    private BookRepository bookRepository;

    public Book findBook(int id) {
        return bookRepository.findById(id).orElse(null);
    }

    public Book findBook(String code) {
        return bookRepository.findByCode(code);
    }

    public Page<Book> findBooks(int page, int pageSize) {
        return bookRepository.findAll(PageRequest.of(page - 1, pageSize));
    }

    public Page<Book> findBooks(int page, int pageSize, int type, String name, int[] state) {
        Pageable paginator = PageRequest.of(page - 1, pageSize);
        return bookRepository.findAll((Specification<Book>) (root, query, criteria) -> {
            Path<String> typePath = root.get("type");
            Path<String> namePath = root.get("name");
            Path<String> statePath = root.get("borrowedUser");
            List<Predicate> predicates = new ArrayList<>();
            if (type > 0) {
                BookType bookType = new BookType();
                bookType.setId(type);
                predicates.add(criteria.equal(typePath, bookType));
            }
            if (name != null && !name.isEmpty()) {
                predicates.add(criteria.like(namePath, "%" + name + "%"));
            }
            if (state.length == 1) {
                if (state[0] == 0) predicates.add(criteria.isNull(statePath));
                else predicates.add(criteria.isNotNull(statePath));
            }
            return criteria.and(predicates.toArray(new Predicate[0]));
        }, paginator);
    }

    @Transactional
    public Book addBook(Book book) {
        if (book.getId() != null) return null;
        return bookRepository.save(book);
    }

    @Transactional
    public Book updateBook(Book book) {
        if (book.getId() == null) return null;
        return bookRepository.save(book);
    }

    @Transactional
    public void deleteBook(int id) {
        bookRepository.deleteByIdAndBorrowedUserIsNotNull(id);
    }
}
